/** 
 * 基础类型定义
 * 定义变量的时候指定类型
*/

// 定义 布尔类型
let isDone: boolean = true
// isDone = 11 错误的写法
isDone = false // 正确

// 定义数值
let decNum: number = 6
let hexNum: number = 0xf00d
let binNum: number = 0b1010
let octNum: number = 0o744

// 定义字符串类型
let firstName: string = `Gene`
let age = 18
let sentence = `Hello, my name is ${name}.

I'll be ${age + 1} years old next month.
`

// 定义数组
// 定义数组的第一种方式
let arr: number[] = [1, 2, 3]

// 定义数组的第二种方式
let names: Array<String> = ['tom', 'jerry']

// 定义元组 Tuple
let score: [string, number];
score = ['10001', 100] // 正确写法
// score = [100, 'hello'] 错误写法

// 定义枚举
// 默认情况下 从 0 开始为元素编号
enum Color {Red, Green, Blue}
let color = Color.Red
// 可以手动指定成员的值
enum State {On=1, Off=0}
let currState: string = State[0]

// 不清楚定义的变量是什么类型 Any
// 可以指定任意类型
let notSure: any = 4
notSure = true
let list: any[] = ['tom', 100, true]
console.log(list[1])

// 没有任何类型：如没有返回值的函数 Void
function printFun(char: string): void {
    console.log(char)
}
// 如果一个变量定义为 void 类型，那么你是能把这个变量赋值为 undefined 或者 null
let unusable: void = undefined
// unusable = 123 错误

// Null 和 Undefined 
let u: undefined = undefined
let n: null = null

// 默认情况下，null 和 undefined 是任何类型的子类型，可以把 null 和 undefined 赋值给任何类型的变量

// Never 类型表示那些永远不存在的值的类型
// never 类型是那些总是会抛出异常或根本不会有返回值的函数表达式或箭头函数表达式的返回值类型
// 变量也有可能是 never 类型，当它们被永远不为真的类型保护所约束时
// never 类型是任何类型的子类型，也可以赋值给任何类型
// 没有类型是 never 的子类型或者可以赋值给 never 类型（除了 never 本身之外，any 类型也不能赋值给 never 类型）

// 下面是一些返回 naver 类型的函数

// 返回 never 的函数必须存在无法到达的终点
function error(message: string): never {
    throw new Error(message)
}

// 推断的返回值类型为 never
function fail() {
    return error('Something failed')
}

// 返回 never 的函数必须存在无法到达的终点
function infiniteLoop(): never {
    while(true) {}
}

// Object 表示非原始类型
// 也就是除 number、string、boolean、symbol、null 或 undefined 之外的类型

// 使用 Object 类型，可以更好的表示像 Object.create 这样的 API
declare function create(o: Object | null): void

create({ prop: 0 }); // OK
create(null); // OK

// create(42); // Error
// create("string"); // Error
// create(false); // Error
// create(undefined); // Error

// 类型断言
// 第一种形式：使用<>
let str: any = "this is a string"
let strLen: number = (<string>str).length

// 第二种形式
strLen = (str as string).length

// 两种方式是完全等价的
// 区别：在 TS 中使用 JSX 语法时，只有 as 语法的断言是被允许的
